# coding=utf-8
# -*- coding: UTF-8 -*-
#
# This file is part of the kernelstudio package.
#
# (c) 2014-2025 zlin <admin@kernelstudio.com>
#
# For the full copyright and license information, please view the LICENSE file
# that was distributed with this source code.

import typing as t
from http import HTTPStatus

from flask import jsonify, current_app
from werkzeug.exceptions import HTTPException

from ksai.context import ApplicationException
from ksai.web.requests import is_ajax_request
from ksai.web.responses import ApiResponse
from ksai.web.template import render_error

error_code_message_mappings = {
    400: '请求错误.',
    401: '访问未授权.',
    404: '请求的资源不存在.',
    405: '请求方式不支持.',
    415: '请求类型不支持.',
    403: '无权限访问此资源.',
    413: '请求大小超过限制.',
}


class NotFoundException(ApplicationException):

    def __init__(self, message: t.Optional[str] = "请求的资源不存在.", code: t.Optional[str] = "404",
                 status: t.Optional[int] = 404):
        super().__init__(message, code, status)


class BadRequestException(ApplicationException):
    def __init__(self, message: t.Optional[str] = "请求错误.", code: t.Optional[str] = "400",
                 status: t.Optional[int] = 400):
        super().__init__(message, code, status)


class UnauthorizedException(ApplicationException):
    def __init__(self, message: t.Optional[str] = "访问未授权.", code: t.Optional[str] = "401",
                 status: t.Optional[int] = 401):
        super().__init__(message, code, status)


class ForbiddenException(ApplicationException):

    def __init__(self, message: t.Optional[str] = "无权限访问此资源.", code: t.Optional[str] = "403",
                 status: t.Optional[int] = 403):
        super().__init__(message, code, status)


class UploadFileException(BadRequestException):

    def __init__(self, message: t.Optional[str] = "上传文件出现错误.", code: t.Optional[str] = "400",
                 status: t.Optional[int] = 400):
        super().__init__(message, code, status)


class UploadFileRequiredException(UploadFileException):

    def __init__(self, message: t.Optional[str] = "上传文件不能为空.", code: t.Optional[str] = "400",
                 status: t.Optional[int] = 400):
        super().__init__(message, code, status)


class UploadTooManyFilesException(UploadFileException):

    def __init__(self, message: t.Optional[str] = "上传文件数量超过限制.", code: t.Optional[str] = "400",
                 status: t.Optional[int] = 400):
        super().__init__(message, code, status)


class UploadFilenameRequiredException(UploadFileException):
    def __init__(self, message: t.Optional[str] = "上传文件名称不能为空.", code: t.Optional[str] = "400",
                 status: t.Optional[int] = 400):
        super().__init__(message, code, status)


class UploadRemoteFileException(UploadFileException):
    def __init__(self, message: t.Optional[str] = "上传文件错误.", code: t.Optional[str] = "400",
                 status: t.Optional[int] = 400):
        super().__init__(message, code, status)


class UploadPersistenceException(UploadFileException):
    def __init__(self, message: t.Optional[str] = "保存文件错误.", code: t.Optional[str] = "400",
                 status: t.Optional[int] = 400):
        super().__init__(message, code, status)


class UploadUnsupportedMimeException(UploadFileException):
    def __init__(self, message: t.Optional[str] = "上传文件类型错误.", code: t.Optional[str] = "400",
                 status: t.Optional[int] = 400):
        super().__init__(message, code, status)


class UploadSizeOverLimitedMimeException(UploadFileException):
    def __init__(self, message: t.Optional[str] = "上传文件大小超过限制.", code: t.Optional[str] = "400",
                 status: t.Optional[int] = 400):
        super().__init__(message, code, status)


def translate_message(e, code: int = 400, message: t.Optional[str] = None):
    if code in error_code_message_mappings:
        return error_code_message_mappings[code]
    return message


def create_api_response_exception(e: Exception) -> ApiResponse:
    status = 500
    code = "500"
    message = "Unknown error"

    # 处理 HTTP 异常
    if isinstance(e, HTTPException):
        status = e.code
        code = e.code
        message = e.description or HTTPStatus(e.code).name
    elif isinstance(e, ValueError):
        status = 400
        code = "400"
        message = str(e)
    elif isinstance(e, ApplicationException):
        status = e.status
        code = e.code
        message = e.message
    # 处理已知异常
    elif hasattr(e, 'status') and hasattr(e, 'message'):
        status = getattr(e, 'status')
        code = getattr(e, 'code', str(status))
        message = getattr(e, 'message')

    if code is None:
        code = "500"
        status = 500
    message = translate_message(e, code, message)

    return ApiResponse(code=code, status=status, message=message)


def create_exception_response(e: Exception):
    res = create_api_response_exception(e)
    if is_ajax_request() or current_app.config.get('APP_JSON_EXCEPTION', True) is True:
        response = jsonify(res.serialize())
        return response, 200
    return render_error(code=res.code, status=res.status, message=res.message)


def register_json_exception_handlers(app):
    @app.errorhandler(Exception)
    def handle_application_exception(e):
        return create_exception_response(e)
